#pragma once

#include <iostream>
#include <vector>
#include <cassert>

#include <semaphore.h>
#include <pthread.h>

using namespace std;

static const int gcap = 5;
template<class T>
class RingQueue
{
public:
    void P(sem_t& sem)  //获取信号量资源
    {
        int n = sem_wait(&sem);
        assert(n == 0);
        (void)n;
        
    }
    void V(sem_t& sem)  //归还信号量资源
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;

    }
public:
    RingQueue(const int& cap = gcap)
        :_queue(cap),_cap(cap)
    {
        int n = sem_init(&_spaceSem,0,_cap);
        assert(n == 0);
        n = sem_init(&_dataSem,0,0);
        assert(n == 0);
        _ProductorStep = _ConsumerStep = 0;
        pthread_mutex_init(&_pmutex,nullptr);
        pthread_mutex_init(&_cmutex,nullptr);

    }
    void push(const T& in)
    {
        P(_spaceSem);
        pthread_mutex_lock(&_pmutex);

        _queue[_ProductorStep++] = in;
        _ProductorStep %= _cap;

        pthread_mutex_unlock(&_pmutex);
        V(_dataSem);
    }
    void pop(T* out)
    {
        P(_dataSem);
        pthread_mutex_lock(&_cmutex);

        *out = _queue[_ConsumerStep++];
        _ConsumerStep %= _cap;

        pthread_mutex_unlock(&_cmutex);
        V(_spaceSem);
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }
private:
    vector<T> _queue;
    int _cap;   //队列容量
    sem_t _spaceSem;    //生产者信号量，->空间资源
    sem_t _dataSem;     //消费者信号量，->数据资源
    int _ProductorStep; //生产者在环形队列的下标
    int _ConsumerStep;  //消费者在环形队列的下标
    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};